package com.maiji.cloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.maiji.cloud.controller.ShopingOrderController;
import com.maiji.cloud.entities.shopingmall.ShipmentsInfoEntity;
import com.maiji.cloud.entities.shopingmall.ShopingOrder;
import com.maiji.cloud.mapper.ShipmentsInfoMapper;
import com.maiji.cloud.request.shopingmall.OrderPrintReqData;
import com.maiji.cloud.request.shopingmall.ShipmentsInfoReqData;
import com.maiji.cloud.response.BaseDataResDto;
import com.maiji.cloud.response.BaseMetaResDto;
import com.maiji.cloud.response.BaseResDto;
import com.maiji.cloud.response.Status;
import com.maiji.cloud.service.ShipmentsInfoService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.service.ShopingOrderService;
import com.maiji.cloud.utils.Express100Util;
import com.maiji.cloud.utils.UUID_MD5;
import org.apache.commons.lang.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class ShipmentsInfoServiceImpl extends ServiceImpl<ShipmentsInfoMapper, ShipmentsInfoEntity> implements ShipmentsInfoService {

    Logger logger = LoggerFactory.getLogger(ShopingOrderController.class);
    @Autowired
    private ShipmentsInfoMapper shipmentsInfoMapper;
    @Autowired
    private ShopingOrderService shopingOrderService;
    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public BaseResDto orderPrintUpdate(OrderPrintReqData orderPrint) {
        String[] orderNos = orderPrint.getOrderNo().split(";");
        ShipmentsInfoEntity shipmentsInfoEntity = new ShipmentsInfoEntity().setTel(orderPrint.getTel())
                .setSendAddress(orderPrint.getAdr()).setConsignee(orderPrint.getConsignee());
        if (! update(shipmentsInfoEntity, new EntityWrapper<ShipmentsInfoEntity>().in("order_no", orderNos)))
            return new BaseResDto(Status.ERROR);
        String[] uuIds = orderPrint.getUuId().split(";");
        List<ShipmentsInfoEntity> shipmentsInfoEntities = Arrays.asList(uuIds).parallelStream().map(uuId -> new ShipmentsInfoEntity().setUuId(uuId)
                .setExpressNo(orderPrint.getExpressNo()).setCompanyCode(orderPrint.getCompanyCode())).collect(Collectors.toList());
        if (! updateBatchById(shipmentsInfoEntities)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto orderPrintManual(OrderPrintReqData orderPrint) {
        List<ShipmentsInfoEntity> shipmentsInfoEntities = Lists.newArrayList();
        Set<ShopingOrder> shopingOrders = Sets.newHashSet();
        String[] orderIds = orderPrint.getOrderId().split(";");
        if (shopingOrderService.selectBatchIds(Arrays.asList(orderIds)).parallelStream().anyMatch(order ->
                order.getRefundStatus() != -1)) return new BaseResDto(Status.ORDERREFUND);
        String[] orderNos = orderPrint.getOrderNo().split(";");
        String[] expressNos = orderPrint.getExpressNo().split(";");
        String[] sendWeightStrs = orderPrint.getSendWeightStrs().split(";");
        for (int j = 0; j < sendWeightStrs.length; j++) {
            for (int i = 0; i < orderIds.length; i++) {
                shipmentsInfoEntities.add(new ShipmentsInfoEntity().setUuId(UUID_MD5.getUUID()).setTel(orderPrint.getTel())
                        .setOrderId(orderIds[i]).setOrderNo(orderNos[i]).setCompanyName(orderPrint.getCompanyName())
                        .setNickName(orderPrint.getNickName()).setExpressStatus(false).setExpressCount(orderPrint.getCount())
                        .setWeight(Integer.valueOf(sendWeightStrs[j])).setWeightTotal(orderPrint.getWeightTotal()).setExpressNo(expressNos[j])
                        .setCompanyCode(orderPrint.getCompanyCode()).setSendAddress(orderPrint.getAdr()).setConsignee(orderPrint.getConsignee()));
                shopingOrders.add(new ShopingOrder().setUuId(orderIds[i]).setStatus(1).setPrinted(true).setPrintDate(new Date()));
            }
        }
        if (! insertBatch(shipmentsInfoEntities)) return new BaseResDto(Status.ERROR);
        if (! shopingOrderService.updateBatchById(new ArrayList<>(shopingOrders))) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<List<ShipmentsInfoEntity>> orderPrintAll(List<OrderPrintReqData> data) {
        Long millis = System.currentTimeMillis();
        logger.info("orderPrintAll =={}==>> data = {}", millis, JSON.toJSONString(data));
        Set<String> orderIds = data.parallelStream().flatMap(orderPrint -> Arrays.asList(
                orderPrint.getOrderId().split(";")).parallelStream()).collect(Collectors.toSet());
        if (shopingOrderService.selectBatchIds(orderIds).parallelStream().anyMatch(order ->
                order.getRefundStatus() != -1)) return new BaseDataResDto(Status.ORDERREFUND);
        data.stream().forEach(orderPrint -> Express100Util.expressPrint(orderPrint));
        if (data.parallelStream().anyMatch(orderPrint -> orderPrint.getExpressPrintData() == null)) {
            String printErrorMsg = data.parallelStream().map(OrderPrintReqData::getPrintErrorMsg).collect(Collectors.joining("；"));
            return new BaseDataResDto<>(Status.PRINTERROR.setMessage(printErrorMsg));
        }
        // 判断是否为发货后重新打印
        List<String> delOrderIds = data.parallelStream().filter(orderPrint -> orderPrint.getStatus() > 1).map(OrderPrintReqData::getOrderId).collect(Collectors.toList());
        if (delOrderIds.size() > 0) {
            if (! delete(new EntityWrapper<ShipmentsInfoEntity>().in("order_id", delOrderIds))) return new BaseDataResDto<>(Status.ERROR);
            List<ShopingOrder> orderList = delOrderIds.parallelStream().map(orderId -> new ShopingOrder().setUuId(orderId).setStatus(1)).collect(Collectors.toList());
            if (! shopingOrderService.updateBatchById(orderList)) return new BaseDataResDto<>(Status.ERROR);
        }
        List<ShipmentsInfoEntity> shipmentsInfoEntities = orderPrint(data);
        if (shipmentsInfoEntities == null) return new BaseDataResDto<>(Status.ERROR);
        List<ShipmentsInfoEntity> shipmentsInfoEntityList = shipmentsInfoEntities.parallelStream().collect(Collectors.toSet()).parallelStream().collect(Collectors.toList());
        logger.info("orderPrintAll =={}==>> SUCCESS", millis);
        return new BaseDataResDto<List<ShipmentsInfoEntity>>(Status.SUCCESS).setData(shipmentsInfoEntityList);
    }

    @Override
    public BaseDataResDto<ShipmentsInfoEntity> orderPrintAdd(OrderPrintReqData data) {
        if (BooleanUtils.isFalse(data.getManualAdd())) {
            Express100Util.expressPrint(data);
            if (data.getExpressPrintData() == null) return new BaseDataResDto<>(Status.ERROR);
        }
        String [] orderIds = data.getOrderId().split(";");
        Wrapper wrapper0 = new EntityWrapper<ShipmentsInfoEntity>().in("order_id", orderIds);
        if (! update(new ShipmentsInfoEntity().setExpressCount(data.getCount()), wrapper0))
            return new BaseDataResDto<>(Status.ERROR);
        List<String> uuIds = Arrays.asList(data.getUuId().split(";"));
        Wrapper wrapper1 = new EntityWrapper<ShipmentsInfoEntity>().in("uu_id", uuIds);
        if (! update(new ShipmentsInfoEntity().setWeight(data.getWeight() - data.getSendWeight()), wrapper1))
            return new BaseDataResDto<>(Status.ERROR);
        List<ShipmentsInfoEntity> shipmentsInfos = Lists.newArrayList();
        if (BooleanUtils.isFalse(data.getManualAdd())) shipmentsInfos = orderPrint(Arrays.asList(data));
        else {
            String [] orderNos = data.getOrderNo().split(";");
            for (int i = 0; i < orderIds.length; i++)
                shipmentsInfos.add(new ShipmentsInfoEntity().setOrderNo(orderNos[i]).setOrderId(orderIds[i])
                    .setNickName(data.getNickName()).setExpressCount(data.getCount()).setTel(data.getTel())
                    .setExpressNo(data.getExpressNo()).setConsignee(data.getConsignee()).setExpressStatus(false)
                    .setCompanyCode(data.getCompanyCode()).setSendAddress(data.getAdr()).setWeight(data.getSendWeight())
                    .setUuId(UUID_MD5.getUUID()).setCompanyName(data.getCompanyName()).setWeightTotal(data.getWeightTotal()));
            if (! insertBatch(shipmentsInfos)) return new BaseDataResDto<>(Status.ERROR);
            List<ShopingOrder> shopingOrders = Arrays.asList(orderIds).parallelStream()
                    .map(orderId -> new ShopingOrder().setUuId(orderId).setStatus(1)).collect(Collectors.toList());
            if (! shopingOrderService.updateBatchById(shopingOrders)) return new BaseDataResDto<>(Status.ERROR);
        }
        if (shipmentsInfos.size() == 0) return new BaseDataResDto<>(Status.ERROR);
        return new BaseDataResDto<ShipmentsInfoEntity>(Status.SUCCESS).setData(shipmentsInfos.get(0));
    }

    @Override
    public BaseDataResDto<ShipmentsInfoEntity> orderPrintNew (OrderPrintReqData orderPrint) {
        List<String> siIds = Arrays.asList(orderPrint.getUuId().split(";"));
        if (siIds.size() > 0) deleteBatchIds(siIds);
        Express100Util.expressPrint(orderPrint);
        List<ShipmentsInfoEntity> shipmentsInfoEntities = orderPrint(Arrays.asList(orderPrint));
        if (shipmentsInfoEntities == null) return new BaseDataResDto<>(Status.ERROR);
        ShipmentsInfoEntity shipmentsInfoEntity = shipmentsInfoEntities.parallelStream().findFirst().get();
        return new BaseDataResDto<ShipmentsInfoEntity>(Status.SUCCESS).setData(shipmentsInfoEntity);
    }

    public List<ShipmentsInfoEntity> orderPrint(List<OrderPrintReqData> data) {
        List<ShipmentsInfoEntity> shipmentsInfoEntities = Lists.newArrayList();
        List<ShopingOrder> shopingOrders = Lists.newArrayList();
        data.parallelStream().forEach(orderPrint -> {
            HashMap expressPrintData = orderPrint.getExpressPrintData();
            List<String> imgBase64s = JSON.parseObject(expressPrintData.get("imgBase64").toString(), List.class);
            String[] orderIds = orderPrint.getOrderId().split(";");
            String[] orderNos = orderPrint.getOrderNo().split(";");
            for (int i = 0; i < orderIds.length; i++) {
                shipmentsInfoEntities.add(new ShipmentsInfoEntity().setUuId(UUID_MD5.getUUID())
                        .setNickName(orderPrint.getNickName()).setWeightTotal(orderPrint.getWeightTotal())
                        .setOrderId(orderIds[i]).setOrderNo(orderNos[i]).setTel(orderPrint.getTel()).setExpressStatus(false)
                        .setImgBase64("data:image/jpeg;base64," + imgBase64s.get(0).replaceAll("[\\t\\n\\r]", ""))
                        .setCompanyCode(expressPrintData.get("kuaidicom").toString()).setCompanyName(orderPrint.getCompanyName())
                        .setExpressNo(expressPrintData.get("kuaidinum").toString()).setSendAddress(orderPrint.getAdr()).setPrintDate(new Date())
                        .setWeight(orderPrint.getSendWeight()).setExpressCount(orderPrint.getCount()).setConsignee(orderPrint.getConsignee()));
                shopingOrders.add(new ShopingOrder().setUuId(orderIds[i]).setStatus(1).setPrinted(true).setPrintDate(new Date()));
            }
        });
        if (! insertBatch(shipmentsInfoEntities)) return null;
        if (! shopingOrderService.updateBatchById(shopingOrders)) return null;
        return shipmentsInfoEntities;
    }

    @Override
    public BaseMetaResDto<List<List<ShipmentsInfoEntity>>> findAllShipmentsInfos(ShipmentsInfoReqData data) {
        List<ShipmentsInfoEntity> shipmentsInfos = shipmentsInfoMapper.findAllShipInfos(data);
        if (shipmentsInfos.size() == 0) return new BaseMetaResDto<>(Status.SUCCESS);
        List<String> orderIds = shipmentsInfos.parallelStream().map(ShipmentsInfoEntity::getOrderId).collect(Collectors.toList());
        List<ShopingOrder> shopingOrders = shopingOrderService.selectBatchIds(orderIds);
        List<String> refundOrderIds = shopingOrders.parallelStream().filter(order ->
                order.getRefundStatus() != -1).map(ShopingOrder::getUuId).collect(Collectors.toList());
        if (refundOrderIds.size() > 0) delete(new EntityWrapper<ShipmentsInfoEntity>().in("order_id", refundOrderIds));
        Map<String, Boolean> rsMap = shopingOrders.parallelStream().collect(Collectors.toMap(ShopingOrder::getUuId, ShopingOrder::getRemindSend));
        Map<String, List<ShipmentsInfoEntity>> shipmentsInfosMap = shipmentsInfos.parallelStream().filter(si -> ! refundOrderIds.contains(si.getOrderId()))
                .map(si -> si.setRemindSend(rsMap.get(si.getOrderId()))).collect(Collectors.groupingBy(ShipmentsInfoEntity::getExpressNo));
        List<List<ShipmentsInfoEntity>> dataList = new ArrayList<>(shipmentsInfosMap.values());
        return new BaseMetaResDto<List<List<ShipmentsInfoEntity>>>(Status.SUCCESS).setData(dataList);
    }

    @Override
    public BaseResDto  orderSend(List<ShipmentsInfoEntity> shipmentsInfos) {
        Set<String> orderIds = shipmentsInfos.parallelStream().map(si -> si.getOrderId()).collect(Collectors.toSet());
        List<ShopingOrder> shopingOrders = shopingOrderService.selectList(new EntityWrapper<ShopingOrder>().in("uu_id", orderIds));
        List<String> refundOrderIds = shopingOrders.parallelStream().filter(order ->
                order.getRefundStatus() != -1).map(ShopingOrder::getUuId).collect(Collectors.toList());
        if (refundOrderIds.size() > 0) delete(new EntityWrapper<ShipmentsInfoEntity>().in("order_id", refundOrderIds));
        List<ShipmentsInfoEntity> finalShipmentsInfos = shipmentsInfos;
        shopingOrders = shopingOrders.parallelStream().filter(order -> order.getRefundStatus() == -1).map(order -> {
            ShipmentsInfoEntity shipmentsInfo = finalShipmentsInfos.parallelStream().filter(si -> si.getOrderId().equals(order.getUuId())).findFirst().get();
            return order.setSendDate(new Date()).setStatus(2).setDelivery(shipmentsInfo.getCompanyName()).setAutoReceive(false);
        }).collect(Collectors.toList());
        if (shopingOrders.size() > 0) if (! shopingOrderService.updateBatchById(shopingOrders)) return new BaseResDto(Status.ERROR);
        shipmentsInfos = shipmentsInfos.parallelStream().filter(si -> ! refundOrderIds.contains(si.getOrderId()))
                .map(si -> si.setSendDate(new Date()).setExpressStatus(true)).collect(Collectors.toList());
        if (shipmentsInfos.size() > 0) if (! updateBatchById(shipmentsInfos)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<Integer> findAllShopingOrderSendStatusCount() {
        Integer count = shipmentsInfoMapper.shopingOrderSendStatusCount();
        return new BaseDataResDto<Integer>(Status.SUCCESS).setData(count);
    }

    @Override
    public BaseDataResDto<HashMap> find_setPrinterModel(HashMap map) {
         if (map.keySet().size() == 0) {
            HashMap printer_model = mongoTemplate.findOne(new Query(), HashMap.class, "printer_model");
            return new BaseDataResDto<HashMap>(Status.SUCCESS).setData(printer_model);
        } else {
            mongoTemplate.findAndRemove(new Query(), HashMap.class, "printer_model");
            mongoTemplate.save(map, "printer_model");
            return new BaseDataResDto<>(Status.SUCCESS);
        }
    }

}
